# ----------------------------------------------------------------------------
#       Copyright (C) 2013-2014 Huynh Vi Lam  <domovilam@gmail.com>
#
#       This file is part of pimucha.
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#	
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#	
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------



# ----------------------------------------------------------------------------
# Use to send and receive X10 raw data over powerline and RF
# from CM15A interface
# Python version 2.7.x and 3.x
# ----------------------------------------------------------------------------
# Software MOCHAD
# ---------------
# - Website: http://sourceforge.net/apps/mediawiki/mochad/index.php?title=Main_Page
# - MOCHAD is used as base for development of scripts
#
# Software CM15ademo
# ---------------
# - Website: http://www.eclipsehomeauto.com/
# - CM15ademo is used as base for development of scripts
# ----------------------------------------------------------------------------


import logging
logger = logging.getLogger()

try:
    from .devcomm.devusb import DEVusb
except ImportError as e:
    logger.debug("%s : %s", repr(e.__class__), str(e))
    from .devcomm.devusb0 import DEVusb
from .ctrlfcts.cm15fct import (ackpwfail,requestcmd)


class CM15(DEVusb):
    vendorId = 0x0BC7
    productId = 0x0001

    write_endpoint = 0x02
    read_endpoint = 0x81

    def __init__(self,port=None):
        DEVusb.__init__(self,port)
        self.idcontroller = 'CM15'
        self.setup = False
        self.TXcap = True
        self.RXcap = True
        self._id = '0BC7:0001'
 
    def tsetup(self):
        """
        Setup interface with if needed
           Wait read and flush
           Ack powerfail signal 
           Test write
        """
        self.open()
        logger.debug("%s Starting with tests....",self.idcontroller)
        try:
            data = self.waitread()
        except:
            self.opened = False
        if self.opened:
            if data is None:
                r = requestcmd(self,'STAT')
                if r is None:
                    self.opened = False
                    return False
                logger.debug("Response to STATUS request %s",repr(r))
            elif data[0] == 0xA5:
                if not ackpwfail(self):
                    logger.critical("Unable to ack Powerfail Signal %s",self.idcontroller)
                    self.opened = False
                    return False
            else:
                logger.debug("Data incoming %s",repr(data))
            logger.warning("%s Ready....",self.idcontroller)
            self.device = self.idcontroller + '-' + self.port
            self.setup = True

    def waitread(self):
        logger.debug("%s waiting for reading data....",self.idcontroller)
        n = 0
        while n < 5:
            data = self.read()
            if data:
                return data
            n += 1
        return None

    def chkwrite(self,byte1,byte2):
        n = 0
        seq = [byte1,byte2]
        logger.debug("Write sequence %s ",repr(seq))
        while n < 5:
            res = self.write(seq,0x55)
            if res[0] == 0x55:
                return True
            if res[0] in (0x5A,0x5D):
                logger.debug("While writing to controller, omit incoming data %s",repr(res))
            n += 1
        return False
 
    def request(self,rcmd):
        return requestcmd(self,rcmd)

    def plsend(self,args,msgq=None):
        """
        Sending a command over powerline with header hd if exist
        hu house unit 0x66 = A1
        hf house function 0x64 = A DIM
        hd header byte for DIM/BRIGHT function and amount DIM
        args = hex string
        """
        logger.debug("Function plsend with CM15")
        hu,hf,hd = args.split()
        ack = None
        if self.chkwrite(0x04,int(hu,16)):	#Send house + unit code
            if hd == '0x00':			#Send house + function (ON|OFF) code
                ack = self.chkwrite(0x06,int(hf,16))
            else:
                logger.debug("Function DIM/BRIGHT not yet implemented")
            if ack:
                logger.debug("Successfuly send over powerline %s to controller CM15", repr(args))
                if msgq : msgq.put_nowait([self.idcontroller,'PL',args,'Success'])
                return 
        logger.error("Unable to send %s to controller CM15", repr(args))
        if msgq : msgq.put_nowait([self.idcontroller,'PL',args,'Fail'])
 
    def rfsend(self,cmdseq,msgq=None):
        """
        Sending a command by RF
        hufseq = sequence of 'words' integer
        """
        logger.debug("Function rfsend with CM15")
        if not isinstance(cmdseq, list):
            hufseq = [int(i,16) for i in cmdseq.split()]
        else:
            hufseq = cmdseq
        seq = [0xeb,0x20] + hufseq
        res = self.write(seq,0x55)
        if res:
            logger.debug("Successfuly send over RF %s to interface CM15", repr(hufseq))
            if msgq : msgq.put([self.idcontroller,'RF',cmdseq,'Success'])
        else:
            logger.error("Unable to send %s to interface CM15", repr(hufseq))
            if msgq : msgq.put([self.idcontroller,'RF',cmdseq,'Fail'])

    def rxevent(self,minlen=4,maxlen=50):
        """
        Reading packet data of maxlen bytes over powerline or RF
        Read [93 20 199 2 240]
        evt[0] : first byte / header of event / packet header
               = 0x5A (PL) partial X10 event
               = 0x5D (RF)
        minlen = min lenght of packet default = 4 bytes
        maxlen = max lenght of packet default = 50 bytes
        Cut down in case of duplicate evts (RF only)
        Return ['0x5d', '0x14 0xc7 0x02 0xf0']
        """
        evt = self.read(maxlen)
        #evt = [93, 41, 36, 43, 132, 123, 117, 128, 93, 41, 36, 43, 132, 123, 117, 128, 93, 41, 36, 43, 132, 123, 117, 128, 93, 41, 36, 43, 132, 123, 117, 128]
        if not evt:
            return None
        if len(evt) < minlen:
            logger.warning("Event %s lenght shorter than min size (%s), omitting this read",repr(evt),minlen)
            return None
        if evt[0] not in (0x5A,0x5D):
            logger.warning("Event other than PL or RF, omitting this read %s",repr(evt))
            return None
        if evt[0] == 0x5A:
            return " ".join(["0x%02x" % i for i in evt])
        # evt[0] == 0x5D:
        n = evt.count(evt[0])
        if n == 1:
            return " ".join(["0x%02x" % i for i in evt])
        events = []
        for i in range(0,n-1):
            event = evt[0:evt[1:].index(0x5D)+1]
            if event not in events:
                events.append(event)
            del evt[0:evt[1:].index(0x5D)+1]
        evts = []
        for e in events:
            evts.append(" ".join(["0x%02x" % i for i in e]))
        return '|'.join(evts)
